﻿namespace DynaPrecision.StandardFunction
{
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using FunctionAnalysis;
	/// <summary>
	/// 
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class Polynomial<T> : IFunction<T, T>
	{
		private List<T> _parameters;


		public Polynomial()
		{
			_parameters = new List<T>();
		}
		public Polynomial(IList<int> orders, IList<T> coefficients)
			: this()
		{
			for (int i = 0; i < orders.Count && i < coefficients.Count; i++)
			{
				this.SetOrder(orders[i], coefficients[i]);
			}
		}

		public IEnumerable<int> Orders
		{
			get
			{
				for (int i = 0; i < _parameters.Count; i++)
				{
					if ((dynamic)_parameters[i] != 0)
					{
						yield return i;
					}
				}

			}
		}
		public IEnumerable<T> Coefficients
		{
			get
			{
				return _parameters.Where(x => (dynamic)x != 0);
			}
		}
		public void SetOrder(int order, T coefficient)
		{
			if (order < _parameters.Count)
			{
				_parameters[order] = coefficient;
			}
			else if (order == _parameters.Count)
			{
				_parameters.Add(coefficient);
			}
			else
			{
				for (int i = _parameters.Count; i < order; i++)
				{
					_parameters.Add(DefaultValueProvider<T>.GetZero());
				}
				SetOrder(order, coefficient);
			}
		}

		#region IFunction<T,T> Members

		public Func<T, T> Functor
		{
			get
			{
				return (x =>
				{
					dynamic _sum = DefaultValueProvider<T>.GetZero(), _current = DefaultValueProvider<T>.GetValueFromInteger(1);
					for (int i = 0; i < _parameters.Count; i++)
					{
						_sum += _current * _parameters[i];
						_current *= x;
					}
					return _sum;
				});
			}
		}

		public IFunction<T, T> Derivative
		{
			get
			{
				Polynomial<T> result = new Polynomial<T>();
				for (int i = 1; i < _parameters.Count; i++)
				{
					dynamic tmp = i;
					result.SetOrder(i - 1, tmp * _parameters[i]);
				}
				return result;
			}
		}

		public IFunction<T, T> Integral
		{
			get { throw new NotImplementedException(); }
		}

		#endregion

		#region Operator overloading
		public static Polynomial<T> operator *(Polynomial<T> poly, T rightValue)
		{
			return new Polynomial<T>(
				poly.Orders.ToList(),
				poly.Coefficients.Select(t => (T)((dynamic)t * rightValue)).ToList());

		}
		#endregion Operator overloading
	}
}